package com.hand.llq25404;

import org.apache.commons.codec.binary.Base64;

import java.security.*;
import java.security.interfaces.RSAPrivateKey;
import java.security.interfaces.RSAPublicKey;

/**
 * @ClassName: RSA
 * @Description: 使用私钥签名、公钥解签。可以防止消息被篡改。
 * @Author: liqun.long@hand-china.com (龙立群)
 * @date: 2019/11/30 14:41
 * @Version 1.0
 */
public class RSA {

    //使用RSA算法加密、SHA算法签名
    public static final String SIGN_ALGORITHMS = "SHA1WithRSA";

    public static void main(String[] args) throws Exception {
        String content = "study hard and make progress everyday";
        System.out.println("原文 :" + content);
        //生成密钥
        KeyPair keyPair = getKeyPair();
        RSAPublicKey publicKey = (RSAPublicKey)keyPair.getPublic();
        RSAPrivateKey privateKey = (RSAPrivateKey)keyPair.getPrivate();
        String sha1Sign = getSha1Sign(content, privateKey);
        System.out.println("rsa签名 :" + sha1Sign);
        boolean sha1Verifty = verifyWhenSha1Sign(content, sha1Sign, publicKey);
        System.out.println("数据是否正确 :" + sha1Verifty);
    }

    /**
     * 生成密钥对
     * @return 密钥对
     * @throws Exception
     */
    public static KeyPair getKeyPair() throws NoSuchAlgorithmException {
        KeyPairGenerator keyGen = KeyPairGenerator.getInstance("RSA");
        //初始化密钥对生成器，密钥最小长度为512位
        keyGen.initialize(512);
        KeyPair keyPair = keyGen.generateKeyPair();
        return keyPair;
    }


    /**
     * 用md5生成内容摘要，再用RSA的私钥加密，进而生成数字签名
     * @param content 原文
     * @param privateKey RSA私钥
     * @return 签名完成后的数据
     * @throws Exception
     */
    public static String getMd5Sign(String content, RSAPrivateKey privateKey) throws Exception {
        byte[] contentBytes = content.getBytes("utf-8");
        Signature signature = Signature.getInstance(SIGN_ALGORITHMS);
        signature.initSign(privateKey);
        signature.update(contentBytes);
        byte[] signs = signature.sign();
        return Base64.encodeBase64String(signs);
    }


    /**
     * 对于使用md5和RSA私钥生成的数字签名进行解签验证
     * @param content 数据签名
     * @param sign 内容
     * @param publicKey 公钥
     * @return 验证数据的正确性
     * @throws Exception
     */
    public static boolean verifyWhenMd5Sign(String content, String sign, RSAPublicKey publicKey) throws Exception {
        byte[] contentBytes = content.getBytes("utf-8");
        Signature signature = Signature.getInstance(SIGN_ALGORITHMS);
        signature.initVerify(publicKey);
        signature.update(contentBytes);
        return signature.verify(Base64.decodeBase64(sign));
    }

    /**
     * 用sha1算法生成内容摘要，再用RSA的私钥加密，进而生成数字签名
     * @param content 原文
     * @param privateKey 私钥
     * @return 数字签名之后的数据
     * @throws Exception
     */
    public static String getSha1Sign(String content, RSAPrivateKey privateKey) throws Exception {
        //编码规则
        byte[] contentBytes = content.getBytes("utf-8");
        //数字签名
        Signature signature = Signature.getInstance(SIGN_ALGORITHMS);
        signature.initSign(privateKey);
        signature.update(contentBytes);
        byte[] signs = signature.sign();
        return Base64.encodeBase64String(signs);
    }

    /**
     * 对于使用shal和RSA私钥生成的数字签名进行解密验证
     * @param content   原文
     * @param sign 加密后的数字签名
     * @param publicKey 公钥
     * @return 数据的正确与否
     * @throws Exception
     */
    public static boolean verifyWhenSha1Sign(String content, String sign, RSAPublicKey publicKey) throws Exception {
        byte[] contentBytes = content.getBytes("utf-8");
        Signature signature = Signature.getInstance(SIGN_ALGORITHMS);
        signature.initVerify(publicKey);
        signature.update(contentBytes);
        return signature.verify(Base64.decodeBase64(sign));
    }

}
